/**
 * 
 */
package pers.vic.elasticsearch.autoconfigure;

import java.io.IOException;
import java.util.stream.Stream;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.util.Asserts;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import pers.vic.elasticsearch.helper.EsDocumentHelper;
import pers.vic.elasticsearch.helper.EsSearchHelper;
import pers.vic.elasticsearch.helper.IndexHelper;

/**
 * @description: ElasticSearch 自动装配入口
 * @author Vic.xu
 * @date: 2020年9月10日下午5:51:12
 */
@Configuration
//设置个开关
@ConditionalOnExpression("${es.enabled:true}")
@ConditionalOnClass(value = RestHighLevelClient.class)
@EnableConfigurationProperties(value = EsProperties.class)
public class EsAutoconfigure {

	private static Logger logger = LoggerFactory.getLogger(EsAutoconfigure.class);

	@Autowired
	private EsProperties esProperties;

	RestHighLevelClient restHighLevelClient;

	IndexHelper indexHelper;

	/**
	 * 创建RestHighLevelClient
	 * 
	 * @link https://juejin.im/post/5d6238b351882559c416112f
	 * @return RestHighLevelClient
	 */
	@Bean
	@Primary
	public RestHighLevelClient restHighLevelClient() {
		if (restHighLevelClient != null) {
			return restHighLevelClient;
		}
		RestClientBuilder restClientBuilder = RestClient.builder(this.createHttpHost());
		restClientBuilder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
			@Override
			public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
				return requestConfigBuilder.setSocketTimeout(esProperties.getTimeout());
			}
		});
		this.restHighLevelClient = new RestHighLevelClient(restClientBuilder);
		return restHighLevelClient;
	}

	/**
	 * 创建 IndexHelper index操作工具类
	 * @return IndexHelper
	 */
	@Bean
	public IndexHelper indexHelper() {
		if (this.indexHelper != null) {
			return this.indexHelper;
		}
		this.indexHelper = new IndexHelper(restHighLevelClient());
		return indexHelper;
	}

	/**
	 * 创建EsDocumentHelper 方便对文档的一些 操作
	 */
	@Bean
	public EsDocumentHelper esDocumentHelper() {
		return new EsDocumentHelper( restHighLevelClient() );
	}

	/**
	 * 创建EsSearchHelper  es搜索操作
	 */
	@Bean
	public EsSearchHelper esSearchHelper() {
		return new EsSearchHelper( restHighLevelClient() );
	}

	/**
	 * 项目启动后创建索引，若不存在的情况下
	 * @throws IOException
	 */
	@PostConstruct
	public void initIndex() throws IOException {
		logger.info("into initIndex...................................");
		IndexConfig[] indexes = esProperties.getIndexes();
		if (indexes == null || indexes.length == 0) {
			return;
		}
		IndexHelper indexHelper = indexHelper();
		int length = indexes.length;
		int existNum = 0;
		int createdNum = 0;
		logger.info("配置的index数目为[{}]", length);
		for (int i = 0; i < length; i++) {
			IndexConfig config = indexes[i];
			if (indexHelper.isExistIndex(config.getName())) {
				existNum++;
				continue;
			}
			logger.info("索引{}不存在, 开始创建!", config.getName());
			indexHelper.createIndex(config);
			createdNum++;
			logger.info("索引{}创建成功!", config.getName());
		}

		logger.info("initIndex finished, existNum=[{}], createdNum=[{}]", existNum, createdNum);
	}

	/**
	 * 项目关闭的时候关闭客户端
	 */
	@PreDestroy
	public void closeClient() throws IOException {
		logger.info("关闭restHighLevelClient客户端");
		restHighLevelClient().close();
	}

	/**
	 * 创建 HttpHost[] 对象
	 * 
	 * @return 返回 HttpHost 对象数组
	 */
	private HttpHost[] createHttpHost() {
		AddressConfig[] address = esProperties.getAddress();
		Asserts.check(!CollectionUtils.isEmpty(address), "ElasticSearch cluster ip address cannot empty");
		HttpHost[] hosts = Stream.of(address).map(addr -> {
			// 此处不校验数据的准确性
			return new HttpHost(addr.getIp(), addr.getPort(), esProperties.getScheme());
		}).toArray(HttpHost[]::new);
		return hosts;
	}

}
